/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ResultEditor.Save;

import ResultEditor.Annotations.Article;
import ResultEditor.Annotations.Depot;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Vector;
import org.jdom.*;
import org.jdom.output.*;

/**
 *
 * @author Chris
 */
public class OutputToXML {
    protected String textsourcefilename;
    protected String path;
    protected Article source = null;
    protected int latestUsedMentionID = 50000;
    protected String absolutepath;

    public OutputToXML( final String textsourcefilename, final String path, Article article){
         this.textsourcefilename = textsourcefilename;
         this.path = path;
         if(article != null)
             source = article;
    }

    /**user try "save" current work to xml files.*/
    public OutputToXML(){
    }

    public void directsave(final File txtfile)
    {
        // ##1##get text source filename
        this.textsourcefilename = txtfile.getName();
        if ( (textsourcefilename == null)||(textsourcefilename.trim().length()<1))
            return;
        
        // ##2## output
        latestUsedMentionID = getLatestUsedMentionID();
        System.out.println(" + now we are try to build xml for text source: ["+ txtfile.getAbsolutePath() + "]");

        File workspace = env.Parameters.WorkSpace.CurrentProject;
        String workspacepath = workspace.getAbsolutePath();
        
        String savedpath = workspacepath + File.separator
                + "saved"+ File.separator;
        System.out.println("["+savedpath+"]");
        File savedFolder = new File(savedpath);

        prepareFolder(savedFolder);

        String xmlpath = savedFolder + File.separator + txtfile.getName().trim()
                + ".knowtator.xml";
        File XMLfile = new File(xmlpath);
        buildxml( XMLfile );

        env.Parameters.forceChangeLatestUsedMentionID(latestUsedMentionID);
    }

    private void prepareFolder(File folder){
        // if folder is a file
        if(folder.exists())
        {
           if(folder.isFile()){
               boolean success = folder.delete();
               if(success){
                    folder.mkdirs();
               }
           }
        }
        else
        {
            folder.mkdirs();
        }
    }

    private String gettextsourcename_byFile(File file){
        if (file==null)
            return null;
        String name = file.getName();
        name = name.toLowerCase().replaceAll(".knowtator.xml", " ");
        name = name.trim();

        return name;
    }

    public boolean write(){
       latestUsedMentionID = getLatestUsedMentionID();
       checkOutputFolder( path );
       String sepatator = ( env.Parameters.isUnixOS? "/":"\\" );
       String outputxmlfilename = path + sepatator + textsourcefilename + ".knowtator.xml";
       System.out.println(" + now we are try to build xml: ["+ outputxmlfilename + "]");

       boolean done = buildxml( textsourcefilename, outputxmlfilename );

       env.Parameters.forceChangeLatestUsedMentionID(latestUsedMentionID);

       return done;
    }

    private boolean buildxml( String textsource, String outputAbsoulateFilename ){
         try{
            // initial the XML file and set the root node of the XML
            //System.out.println("annotationsStr is " + annotationsStr);
            Element root = new Element( "annotations" ); //
            //System.out.println("TextSource is " + TextSource);
            root.setAttribute( "textSource", textsource );
            Document Doc = new Document(root);

            /** add contents */
            root = addAnnotations( root );

            // **** output xml file to disk ****
            // XML storage processing: phycial writing
            Format format = Format.getCompactFormat();
            format.setEncoding("UTF-8"); // set XML encodeing
            format.setIndent("    ");
            XMLOutputter XMLOut = new XMLOutputter(format);
            // write to disk
            FileOutputStream XML = new FileOutputStream( outputAbsoulateFilename );
            XMLOut.output(Doc, XML);
            XML.close();

            // Screen Log
            Logs.ShowLogs.printImportantInfoLog("Successfully genereted XML to - " + outputAbsoulateFilename );
            return true;
         }
        catch(Exception exc){
            // exc.printStackTrace();
            Logs.ShowLogs.printErrorLog("WriteToXML.java - " + exc.toString());
            return false;
        }
    }
    private boolean buildxml( File XMLfile )
    {
         try{
            // initial the XML file and set the root node of the XML
            //System.out.println("annotationsStr is " + annotationsStr);
            Element root = new Element( "annotations" ); //
            //System.out.println("TextSource is " + TextSource);
            root.setAttribute( "textSource", this.textsourcefilename );
            Document Doc = new Document(root);

            /** add contents */
            root = addAnnotations( root );

            // **** output xml file to disk ****
            // XML storage processing: phycial writing
            Format format = Format.getCompactFormat();
            format.setEncoding("UTF-8"); // set XML encodeing
            format.setIndent("    ");
            XMLOutputter XMLOut = new XMLOutputter(format);
            // write to disk
            FileOutputStream XML = new FileOutputStream( XMLfile );
            System.out.println(XMLfile);
            XMLOut.output(Doc, XML);
            XML.close();

            // Screen Log
            System.out.println("Successfully genereted XML to - "
                    + XMLfile );
            return true;
         }
        catch(Exception exc){
            // exc.printStackTrace();
            Logs.ShowLogs.printErrorLog("WriteToXML.java - " + exc.toString());
            return false;
        }
    }

    private Element addAnnotations(Element root)
    {
        ResultEditor.Annotations.Depot depot = new ResultEditor.Annotations.Depot();
        Article article = null;
        if(source == null)
            article = Depot.getArticleByFilename(textsourcefilename);
        else
            article = source;

        if( article == null )
            return root;

        try
        {
            for( ResultEditor.Annotations.Annotation annotation: article.annotations ){
                latestUsedMentionID++;
                int mentionid = latestUsedMentionID;
                annotation.outputmentionid = "EHOST_Instance_"+ mentionid;
            }

            for(ResultEditor.Annotations.Annotation annotation: article.annotations)
            {
                root = buildAnnotationNode(
                        root,
                        annotation.outputmentionid,
                        annotation.annotationText,
                        annotation.annotationclass,
                        annotation.spanstart,
                        annotation.spanend,
                        annotation.creationDate,
                        annotation.comments,
                        annotation.annotator,
                        annotation.annotatorid,
                        annotation.normalrelationships,
                        annotation.ComplexRelationships,
                        annotation.verifierSuggestion,
                        annotation.verifierFound
                        );
            }
        }catch(Exception e){
            System.out.println("error 1102111931::fail to pack annotation to XML"
                    + e.toString() );
            return root;
        }

        return root;
    }

    private Element buildAnnotationNode(Element _root, String _MentionID,
            String _spanText, String _classname, int _start, int _end,
            String creationdate, String annotationComment,
            String _annotator, String annotatorid,
            Vector<ResultEditor.Annotations.NormalRelationship> normalrelationships,
            Vector<ResultEditor.Annotations.ComplexRelationship> complexrelationships,
            Vector<String> verifierSuggestions, //suggestions extracted from annotation comment
            Vector<ResultEditor.Annotations.suggestion> verifierFounds

            //Vector<String> _Slots
            )
    {
            Element root = _root;

            if(_classname==null){
                System.out.println("error 1102111947:: while building the XML node, classname is NULL");
                return root;
            }

            if((_MentionID==null)||(_MentionID.trim().length()<1)){
                System.out.println("error 1102111947:: while building the XML node, mention id is NULL");
                return root;
            }



            // -----------------------------------------------------elements
            Element annotation = new Element("annotation");

            Element mention = new Element("mention");
            //System.out.println("mention id - " + annotationRecor ds.mentionId );
            mention.setAttribute("id",  _MentionID );
            //mention.setAttribute("id", "EHOST_0" );
            annotation.addContent(mention);

            Element annotator = new Element("annotator");
            //annotator.setAttribute("id", "EHOST_607");
            if(annotatorid==null) annotatorid = "eHOST_anonym_001";
            annotator.setAttribute("id", annotatorid);
            //System.out.println("annotator id - " + annotationRecords.annotatorId );
            //annotator.setAttribute("id", "EHOST_12");
            //System.out.println("annotator text - " + annotationRecords.annotator );
            if((_annotator==null)||(_annotator.trim().length()<1)){
                _annotator = "eHOST_anonym";
            }
            annotator.setText(_annotator);
            annotation.addContent(annotator);

            Element span = new Element("span");
            span.setAttribute("start", String.valueOf( _start ));
            span.setAttribute("end", String.valueOf( _end));
            annotation.addContent(span);

            if(_spanText==null)
                _spanText = "";
            annotation.addContent( new Element("spannedText").setText(_spanText));

            //#### handle comment and verifier suggestions here
            String commentstr = handleCommentAndVerifierSuggestions( annotationComment, verifierSuggestions, verifierFounds );            
            if ( commentstr != null ){
                if ( (commentstr.trim().length() > 0) && ( commentstr.replaceAll("\"", " ").trim().length() > 0 ) )
                    annotation.addContent( new Element("annotationComment").setText( commentstr ) );
            }
            
            


            if((creationdate==null)||(creationdate.trim().length()<1))
                creationdate = commons.OS.getCurrentDate();
            annotation.addContent( new Element("creationDate").setText( creationdate ));

            root.addContent(annotation);
            // -----------------------------------------------------elements end


            // -----------------------------------------------------classmention begin
            // "classMention" data structure and get stored data in memory
            Element classMention = new Element("classMention");
            classMention.setAttribute("id", _MentionID );
            Element mentionClass = new Element( "mentionClass" );

            if((_classname==null)||(_classname.trim().length()<1))
                _classname = "UNKNOWN";
            mentionClass.setAttribute( "id", _classname );
            mentionClass.addContent( _spanText );

            //#### add has-string-slot in classmention for normal relationship
            try{
                if ((normalrelationships!=null)&&(normalrelationships.size()>0)){
                    //add this node <ClassMention> to xml tree
                    for( ResultEditor.Annotations.NormalRelationship normalrelationship :  normalrelationships){
                        if(normalrelationship==null)
                            continue;
                        if(   (normalrelationship.relationshipName==null)
                            ||(normalrelationship.relationshipValue==null)
                            ||(normalrelationship.relationshipValue.size()<1)
                            ||(normalrelationship.relationshipName.length()<1)
                        )
                            continue;
                        
                        latestUsedMentionID++;
                        int mentiondid = latestUsedMentionID;
                        Element hasSlotMention = new Element("hasSlotMention");
                        hasSlotMention.setAttribute("id", "EHOST_Instance_" + mentiondid );
                        classMention.addContent(hasSlotMention);

                        Element slot = addstringSlots(
                                "EHOST_Instance_" + mentiondid,
                                normalrelationship.relationshipName,
                                normalrelationship.relationshipValue
                                );
                        if (slot!= null) root.addContent(slot);
                    }
                }
            }catch(Exception e){System.out.println("1-"+e.toString());}

            //#### add has-string-slot in classmention for complex relationship
            try{
                if ( complexrelationships!=null ){
                    //add this node <ClassMention> to xml tree
                    for( ResultEditor.Annotations.ComplexRelationship complexrelationship :  complexrelationships){
                        latestUsedMentionID++;
                        int cmentiondid = latestUsedMentionID;
                        Element hasSlotMention = new Element("hasSlotMention");
                        hasSlotMention.setAttribute("id", "EHOST_Instance_" + cmentiondid );
                        classMention.addContent(hasSlotMention);

                        Element cslot = addComplexSlots(
                                "EHOST_Instance_" + cmentiondid,
                                complexrelationship.getMentionSlotID(),
                                complexrelationship.getLinkedAnnotations()
                                );
                        if (cslot!= null) root.addContent(cslot);
                    }
                }
            }catch(Exception e){System.out.println("2-"+e.toString());}

            // DISABLEDDISABLED
            if(env.Parameters.Output_XML.output_verify_suggestions_toXML){
                if(!hasSuggestions( verifierSuggestions, verifierFounds )){
                    latestUsedMentionID++;
                    int amentiondid = latestUsedMentionID;
                    Element hasSlotMention2 = new Element("hasSlotMention");
                    hasSlotMention2.setAttribute("id", "EHOST_Instance_" + amentiondid );
                    classMention.addContent(hasSlotMention2);

                    Element gslot = addZeroSuggestionSlot(
                                    "EHOST_Instance_" + amentiondid
                                    );
                    if (gslot!= null) root.addContent(gslot);
                }
            }


            classMention.addContent( mentionClass );
            root.addContent( classMention );


            return root;
    }

    private Element addZeroSuggestionSlot( String mentionid ){

        // "classMention" data structure and get stored data in memory
        Element stringSlotMention = new Element("stringSlotMention");
        stringSlotMention.setAttribute("id", mentionid );

        Element mentionSlot = new Element( "mentionSlot" );
        mentionSlot.setAttribute( "id", "suggestion" );
        stringSlotMention.addContent( mentionSlot );

        Element stringSlotMentionValue = new Element( "stringSlotMentionValue" );
        stringSlotMentionValue.setAttribute( "value", "0" );
        stringSlotMention.addContent( stringSlotMentionValue );


        return stringSlotMention;
    }


    private boolean hasSuggestions(  Vector<String> verifierSuggestions, //suggestions extracted from annotation comment
            Vector<ResultEditor.Annotations.suggestion> verifierFounds ) {

        Vector<String> suggestions = new Vector<String>();
        String commentstr = null;
        if( verifierSuggestions != null ){
            for( String suggestion: verifierSuggestions ){
                suggestions.add(suggestion.trim());
            }
        }
        if( verifierFounds != null ){
            for( ResultEditor.Annotations.suggestion suggestion: verifierFounds ){
                suggestions.add(suggestion.getExplanation().trim());
            }
        }

        suggestions =  removeRepetitive( suggestions );

        if (suggestions == null)
            return false;
        else{
            return ( suggestions.size() > 0? true: false);
        }

    }

    private String handleCommentAndVerifierSuggestions(
            String comment,
            Vector<String> verifierSuggestions, //suggestions extracted from annotation comment
            Vector<ResultEditor.Annotations.suggestion> verifierFounds ) {

        Vector<String> suggestions = new Vector<String>();
        String commentstr = null;
        if( verifierSuggestions != null ){
            for( String suggestion: verifierSuggestions ){
                suggestions.add(suggestion.trim());
            }
        }
        if( verifierFounds != null ){
            for( ResultEditor.Annotations.suggestion suggestion: verifierFounds ){
                suggestions.add(suggestion.getExplanation().trim());
            }
        }

        suggestions =  removeRepetitive( suggestions );

        
        // remvoe old instered suggestion
        if( comment != null ){
            comment = comment.replaceAll("(\\()" +
                "( *)" +
                "(VERIFIER_SUGGESTIONS)" +
                "( *)" +
                "(.*)" +
                "(\\))", " ");
            comment = comment.replaceAll("\"", " ");
        }else{
            comment = "";
        }


        String sug = "";
        if ((suggestions != null)&&( suggestions.size() > 0 )) {

            sug = "(VERIFIER_SUGGESTIONS ";
            for( String str: suggestions){
                sug = sug +  "[" + str.trim() + "] ";
            }
            sug = sug + ")";
        }

        return "\"" + sug + " " + comment + "\"";
    }

    private Vector<String> removeRepetitive(Vector<String> list){
        int size = list.size();
        for(int i=0;i<size;i++) {
            for(int j=0;j<size;j++) {
                if(i!=j){
                    if ( list.get(i).compareTo( list.get(j) ) == 0 ){
                        list.set(j, null);
                    }
                }
            }
        }
        Vector<String> newlist = new Vector<String>();
        for(String listentry: list){
            if (listentry != null)
                newlist.add(listentry);
        }

        return newlist;

    }

    private Element addComplexSlots( String mentionid,
            String id, Vector<ResultEditor.Annotations.eComplex> values){


            if(( id == null)||(values == null))
                return null;

            // "classMention" data structure and get stored data in memory
            Element complexSlotMention = new Element("complexSlotMention");
            complexSlotMention.setAttribute("id", mentionid );

            Element mentionSlot = new Element( "mentionSlot" );
            mentionSlot.setAttribute( "id", id );
            complexSlotMention.addContent( mentionSlot );

            for(ResultEditor.Annotations.eComplex value: values){
                if(value == null)
                    return complexSlotMention;
                String linkedAnnotaionMentionID = getMentionID_byIndex( value.linkedAnnotationIndex ) ;
                if ( linkedAnnotaionMentionID == null )
                    continue;
                Element complexSlotMentionValue = new Element( "complexSlotMentionValue" );
                complexSlotMentionValue.setAttribute( "value", linkedAnnotaionMentionID  );
                complexSlotMention.addContent( complexSlotMentionValue );
            }

        return complexSlotMention;
    }

    private String getMentionID_byIndex(int annotationIndex){
        ResultEditor.Annotations.Depot depot = new ResultEditor.Annotations.Depot();
        ResultEditor.Annotations.Article article = depot.getArticleByFilename(textsourcefilename);
        if (article == null)    return null;

        for( ResultEditor.Annotations.Annotation annotation: article.annotations){
            if (annotation.uniqueIndex == annotationIndex )
                return annotation.outputmentionid;

        }
        return null;

    }

    private Element addstringSlots( String mentionid,
            String type, Vector<String> values){

    
            if(( type == null)||(values == null))
                return null;
            
            // "classMention" data structure and get stored data in memory
            Element stringSlotMention = new Element("stringSlotMention");
            stringSlotMention.setAttribute("id", mentionid );

            Element mentionSlot = new Element( "mentionSlot" );
            mentionSlot.setAttribute( "id", type );
            stringSlotMention.addContent( mentionSlot );

            for(String value: values){
                if(value == null) return stringSlotMention;
                
                Element stringSlotMentionValue = new Element( "stringSlotMentionValue" );
                stringSlotMentionValue.setAttribute( "value", value );
                stringSlotMention.addContent( stringSlotMentionValue );
            }

        return stringSlotMention;
    }

    private void checkOutputFolder(String path){
        File folder = new File(path);
        if (!folder.exists()){
            folder.mkdirs();
        }
    }

    private int getLatestUsedMentionID(){
        return env.Parameters.getLatestUsedMentionID();
    }
}
